﻿Imports System.ComponentModel
Namespace Cues
    ''' <summary>
    ''' The types (besides the base) of cues available in the program.
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum Types
        Audio
        Transport
        Stack
    End Enum

    ''' <summary>
    ''' The base class for all types of cues.
    ''' </summary>
    ''' <remarks></remarks>
    <Serializable> Public MustInherit Class CueBase
#Region "Implements"
        Implements INotifyPropertyChanged
        Implements IComparer
        Implements IComparable


#Region "Comparer"

        ''' <summary>
        ''' Compares one cue object to another.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Compare(x As Object, y As Object) As Integer Implements IComparer.Compare
            If TryCast(x, CueBase).Number >= 0 Then
                Return Equals(CType(x, CueBase).Number, CType(y, CueBase).Number)
            Else
                Return New CaseInsensitiveComparer().Compare(x.ToString, y.ToString)
            End If
        End Function

        ''' <summary>
        ''' Compares the current cue object to another.
        ''' </summary>
        ''' <param name="obj">The object to compare this cue with.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
            If Me.Number > CType(obj, CueBase).Number Then
                Return 1
            ElseIf Me.Number < CType(obj, CueBase).Number Then
                Return -1
            Else
                Return 0
            End If
        End Function


        Public Shared Operator >(obj1 As CueBase, obj2 As CueBase) As Boolean
            If obj1.Number > obj2.Number Then
                Return True
            Else
                Return False
            End If
        End Operator
        Public Shared Operator <(obj1 As CueBase, obj2 As CueBase) As Boolean
            If obj1.Number < obj2.Number Then
                Return True
            Else
                Return False
            End If
        End Operator



#End Region

#Region "Notification"
        <NonSerialized()> Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

        Friend Overridable Sub RaisePropertyChanged(ByVal sProp As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(sProp))
            If sProp = "CueList" Then
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("CueListCollection"))
            End If
            If sProp = "Number" AndAlso Me.GetType Is GetType(Cues.Stack) Then
                For Each c In CType(Me, Cues.Stack).CueList
                    c.ParentCue = Me.Number
                Next
            End If
        End Sub
#End Region

#End Region

#Region "Events"

        ''' <summary>
        ''' Raised when the cue is stopped due to it being complete.
        ''' </summary>
        ''' <remarks></remarks>
        Public Event CueStopped(Cue As Cues.CueBase)

        ''' <summary>
        ''' Used by inheriting cue objects to raise the cue stopped event on the base object.
        ''' </summary>
        ''' <param name="Cue"></param>
        ''' <param name="ManualStop"></param>
        ''' <remarks></remarks>
        Protected Sub RaiseCueStopped(Cue As Cues.CueBase, Optional ManualStop As Boolean = False)
            RaiseEvent CueStopped(Cue)
            If TransportAction = CueActions.AdvanceAtEnd AndAlso Not ManualStop Then
                RaiseEvent StartTransportAction(Me, New EventArgs)
            ElseIf ManualStop AndAlso TransportActionTimer IsNot Nothing Then
                TransportActionTimer.Stop()
            End If
        End Sub

        ''' <summary>
        ''' Raised when the cue is ready to fire it's after action.
        ''' </summary> 
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Public Event StartTransportAction(sender As Cues.CueBase, e As EventArgs)

        ''' <summary>
        ''' The timer that sets the delay for TransportActions.
        ''' </summary>
        ''' <remarks></remarks>
        <NonSerialized> Protected WithEvents TransportActionTimer As System.Timers.Timer

        ''' <summary>
        ''' Fires when the after action is ready to start.
        ''' </summary>
        ''' <param name="sender"></param>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub FireTransportActionPause(sender As Object, e As System.Timers.ElapsedEventArgs) Handles TransportActionTimer.Elapsed
            RaiseEvent StartTransportAction(Me, New EventArgs)
            TransportActionTimer.Stop()
        End Sub


#End Region

#Region "Properties"

        Public ReadOnly Property IsActive As Boolean
            Get
                If (TransportActionTimer IsNot Nothing AndAlso TransportActionTimer.Enabled) OrElse Status = CueStatus.Active Then
                    Return True
                Else
                    Return False
                End If
            End Get
        End Property

        ''' <summary>
        ''' Represents the Number Property.
        ''' </summary>
        ''' <remarks></remarks>
        Private NumberProperty As Double

        ''' <summary>
        ''' Identifies the cue number the cue has within the show.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Number As Double
            Get
                Return NumberProperty
            End Get
            Set(value As Double)
                If value <> NumberProperty Then
                    NumberProperty = value
                    RaisePropertyChanged("Number")
                    RaisePropertyChanged("FullNumber")
                End If
            End Set
        End Property

        ''' <summary>
        ''' If the ParentCue property is greater than 0 then this returns a composite of that property and the CueNumber property.
        ''' Otherwise it returns the CueNumber property.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Xml.Serialization.XmlIgnore> Public Property FullNumber As String
            Get
                If ParentCue <> Nothing AndAlso ParentCue <> "-1" AndAlso ParentCue <> "0" AndAlso ParentCue <> "" Then
                    Return ParentCue & ":" & Number
                Else
                    Return Number
                End If
            End Get
            Private Set(value As String)
                'Does nothing
            End Set
        End Property

        Private ParentCueProperty As String = ""
        ''' <summary>
        ''' This should be set if the cue has a parent cue. Generally parent cues will only be StackCues.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ParentCue As String
            Get
                Return ParentCueProperty
            End Get
            Set(value As String)
                If ParentCueProperty <> value Then
                    ParentCueProperty = value
                    RaisePropertyChanged("ParentCue")
                    RaisePropertyChanged("FullNumber")
                End If

            End Set
        End Property

        ''' <summary>
        ''' Represents the Description Property.
        ''' </summary>
        ''' <remarks></remarks>
        Private DescriptionProperty As String = ""
        ''' <summary>
        ''' An optional description that the user can create to describe the cue.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Description As String
            Get
                Return DescriptionProperty
            End Get
            Set(value As String)
                DescriptionProperty = value
                RaisePropertyChanged("Description")
            End Set
        End Property

        ''' <summary>
        ''' The current status of the cue.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Status As CueStatus
            Get
                Return StatusProperty
            End Get
            Set(value As CueStatus)
                If StatusProperty <> value Then
                    StatusProperty = value
                    If Me.GetType Is GetType(Cues.Stack) AndAlso CType(Me, Cues.Stack).CueList.Count > 0 Then
                        If value = CueStatus.Cued Then
                            If CType(Me, Cues.Stack).CueList.Item(0).Status <> CueStatus.Cued Then
                                CType(Me, Cues.Stack).CueList.Item(0).Status = CueStatus.Cued
                            End If
                        ElseIf value = CueStatus.Standby Then
                            For Each c In CType(Me, Cues.Stack).CueList
                                c.Status = CueStatus.Standby
                            Next
                        End If
                    End If
                    If value = CueStatus.Active Then
                        If TransportAction = CueActions.Pause AndAlso ActionDelay > 0 Then
                            If TransportActionTimer Is Nothing Then TransportActionTimer = New Timers.Timer()
                            TransportActionTimer.Interval = ActionDelay * 1000
                            TransportActionTimer.AutoReset = False
                            TransportActionTimer.Start()
                        ElseIf TransportAction = CueActions.Pause AndAlso ActionDelay = 0 Then
                            RaiseEvent StartTransportAction(Me, New EventArgs)
                        End If
                    End If
                    RaisePropertyChanged("Status")
                    If My.Application IsNot Nothing AndAlso My.Application.Show IsNot Nothing AndAlso My.Application.Show.ShowFile IsNot Nothing Then
                        My.Application.Show.ShowFile.RaisePropertyChanged("ActiveCues")
                    End If
                End If
            End Set
        End Property
        ''' <summary>
        ''' Represents the Status Property.
        ''' </summary>
        ''' <remarks></remarks>
        <NonSerialized> Private StatusProperty As CueStatus = CueStatus.Standby

        ''' <summary>
        ''' The action that occurs as soon as the cue is triggered.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property TransportAction As CueActions
            Get
                Return TransportActionProperty
            End Get

            Set(ByVal value As CueActions)
                TransportActionProperty = value
                RaisePropertyChanged("TransportAction")
                RaisePropertyChanged("TransportActionIndex")
            End Set
        End Property

        ''' <summary>
        ''' Used in UI for determining selected TransportAction properly.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property TransportActionIndex As Integer
            Get
                Return CInt(TransportActionProperty)
            End Get
            Set(value As Integer)
                If CInt(TransportActionProperty) <> value Then
                    TransportActionProperty = value
                    RaisePropertyChanged("TransportAction")
                End If
            End Set
        End Property

        ''' <summary>
        ''' Represents the TransportAction Property.
        ''' </summary>
        ''' <remarks></remarks>
        Private TransportActionProperty As CueActions = My.Settings.DefaultAfterAction

        ''' <summary>
        ''' When AfterAction is set to Pause this is the delay before triggering the next cue. Is in seconds.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ActionDelay As Double
            Get
                Return ActionDelayProperty
            End Get
            Set(value As Double)
                If value < 0.1 Then value = 0.1
                If ActionDelayProperty <> value Then
                    ActionDelayProperty = value
                    RaisePropertyChanged("ActionDelay")
                End If
            End Set
        End Property
        ''' <summary>
        ''' Represents the ActionDelay Property.
        ''' </summary>
        ''' <remarks></remarks>
        Private ActionDelayProperty As Double = My.Settings.DefaultDelay

        ''' <summary>
        ''' Represents the CueGUID Property
        ''' </summary>
        ''' <remarks></remarks>
        Private CueGUIDProperty As Guid = Guid.NewGuid()

        ''' <summary>
        ''' A unique Cue ID, guaranteed unique across all cue lists.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property CueGUID As Guid
            Get
                Return CueGUIDProperty
            End Get
        End Property


        Private IsSelectedProperty As Boolean = False
        ''' <summary>
        ''' Indicates whether the cue is selected in a GUI.
        ''' </summary>
        ''' <returns></returns>
        Public Property IsSelected As Boolean
            Get
                Return IsSelectedProperty
            End Get
            Set(value As Boolean)
                IsSelectedProperty = value
                RaisePropertyChanged(NameOf(IsSelected))
            End Set
        End Property

#End Region

#Region "Public Functions"

        ''' <summary>
        ''' Individual cues must override this to provide a relevent info string.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public MustOverride Overrides Function ToString() As String

        ''' <summary>
        ''' Used to prep the cue for processing.
        ''' </summary>
        ''' <remarks></remarks>
        Public MustOverride Sub Standby()


        ''' <summary>
        ''' Used to start the cue's functions.
        ''' </summary>
        ''' <remarks></remarks>
        Public MustOverride Sub Start()

        ''' <summary>
        ''' Used to stop the cue.
        ''' </summary>
        ''' <param name="Bool">Indicates whether the stop should include an optional boolean action.</param>
        ''' <remarks></remarks>
        Public MustOverride Sub [Stop](Optional Bool As Boolean = True)

        ''' <summary>
        ''' If a cue is in standby this moves it to cued and vice-versa. If a cue is active this does nothing.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub BumpStatus()
            Try
                If Status = CueStatus.Standby Then
                    Status = CueStatus.Cued
                ElseIf Status = CueStatus.Cued Then
                    Status = CueStatus.Standby
                End If
            Catch ex As Exception
                My.Application.Show.Console.SendMessage("There was a problem changing the status of cue number: " & Number.ToString, ex)
            End Try
        End Sub

        ''' <summary>
        ''' Creates a new cue, optionally giving it a parent cue number.
        ''' </summary>
        ''' <param name="ParentCueNumber">The cue number of which parent it belongs to.</param>
        ''' <remarks></remarks>
        Public Sub New(Optional ParentCueNumber As String = "-1")
            ParentCue = ParentCueNumber
        End Sub

#End Region

    End Class

    ''' <summary>
    ''' The possible statuses of a cue.
    ''' </summary>
    ''' <remarks></remarks>
    <Serializable> Public Enum CueStatus
        Cued
        Active
        Standby
    End Enum

    ''' <summary>
    ''' The possible actions a cue can take immediately after it's been fired.
    ''' </summary>
    ''' <remarks></remarks>
    <Serializable> Public Enum CueActions As Integer
        [Nothing]
        Pause
        [Next]
        AdvanceAtEnd
    End Enum

End Namespace